package as3GameLib.managers
{
	import as3GameLib.core.KeystrokePattern;
	
	import flash.events.KeyboardEvent;
	import flash.events.TimerEvent;
	import flash.utils.Timer;
	import flash.events.Event;
	
	public class KeystrokeManager implements IKeystrokeManager
	{
		static public var bufferLengthMax:uint = 5;
		static public var bufferLengthMin:uint = 3;
		
		static public var actionKeys:String = "zxcv"; //for most Neo Geo style games, for SF2 type games it could be "fdsvcx"
		
		//////////////////////////////////////////////////
		//	PATTERNS
		//////////////////////////////////////////////////
		
		[ArrayElementType("as3GameLib.core.KeystrokePattern")]
		static private var _patterns:Array = [];
		
		static public function addPattern (pattern:KeystrokePattern):Boolean
		{
			if (!pattern.id || !pattern.pattern || pattern.id == "" || pattern.pattern.length < 1)
				return false;
			
			//check to see if it is in the array already
			var obj:KeystrokePattern;
			for each (obj in _patterns)
			{
				if (obj.id == pattern.id || obj.pattern.toString() == pattern.pattern.toString())
					return false;
			}
			
			//no duplicates so add to array
			_patterns.push(pattern);
			_patterns.sortOn("length", Array.DESCENDING | Array.NUMERIC);//sorting longest patterns to top of list
			
			return true;
		}
		
		static public function getPattern (pattern:*):KeystrokePattern
		{
			//we can use 3 types of data: string id, pattern array or a KeystrokePattern
			var id:String;
			var arr:Array;
			
			if (pattern is String)
				id = pattern;
				
			else if (pattern is Array)
				arr = pattern;
				
			else if (pattern is KeystrokePattern)
			{
				id = pattern.id;
				arr = pattern.pattern;
			}
			
			else
			{
				throw new Error("Pattern parameter must be of class type String, Array or KeystrokePattern.");
				return null
			}
			
			var obj:KeystrokePattern
			for each (obj in _patterns)
			{
				if (obj.id == id || obj.pattern.toString() == arr.toString())
					return obj;
			}
			
			//we didn't find it
			return null;
		}
		
		static public function removePattern (pattern:*):KeystrokePattern
		{
			var p:KeystrokePattern = getPattern(pattern);			
			
			var obj:KeystrokePattern;
			var i:uint;
			var l:uint = _patterns.length;
			for (i; i < l; i++) //gotta find the index to pop it out of array
			{
				obj = KeystrokePattern(pattern[i]);
				if (obj.id == p.id)
					break;
			}
			
			_patterns.splice(i, 1);
			return p;
		}
		
		//////////////////////////////////////////////////
		//	INIT
		//////////////////////////////////////////////////
		
		public function initialize (target:IKeystrokeManagerClient, timerDelay:uint = 100):void
		{
			_client = target;
			
			if (_client.stage)
			{
				_client.stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
				_client.stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
			}
			
			else
				_client.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
			
			_timer = new Timer(timerDelay, 1);
			_timer.addEventListener(TimerEvent.TIMER, onTimer);
		}
		
		private var _client:IKeystrokeManagerClient;
		
		[ArrayElementType("uint")]
		private var _buffer:Array = [];
		
		private var _timer:Timer;
		
		//////////////////////////////////////////////////
		//	EVT HANDLERS
		//////////////////////////////////////////////////
		
		private function onAddedToStage (evt:Event):void
		{
			_client.removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
			
			_client.stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
			_client.stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
		}
		
		//for each key stoke in rapid succession we store to the buffer, then check against any possible pattern matches
		private function onKeyUp (evt:KeyboardEvent):void
		{
			_timer.reset(); //stop the timer and restart it so that we can preserve the buffer for a min time
			_timer.start();
			
			_buffer.push(evt.keyCode);
			
			if (_buffer.length >= KeystrokeManager.bufferLengthMax)
				_buffer.shift();
			
			if (_buffer.length >= KeystrokeManager.bufferLengthMin)
			{
				var regex:RegExp;
				var p:KeystrokePattern;
				for each (p in KeystrokeManager._patterns)
				{
					regex = new RegExp(p.pattern.toString());
					if (regex.test(_buffer.toString()))
					{
						_client.handlePatternMatch(p);
						return;
					}	
				}
			}
			
			_client.keyUp_eventHandler(evt);
		}
		
		private function onKeyDown (evt:KeyboardEvent):void
		{
			_client.keyDown_eventHandler(evt);
		}
		
		private function onTimer (evt:TimerEvent):void
		{
			_buffer = [];
		}
	}
}